package org.loong.crypto.service.software.provider.asymmetric.rsa;

import java.security.interfaces.RSAPublicKey;
import java.security.spec.PSSParameterSpec;

import org.apache.commons.lang3.StringUtils;
import org.loong.crypto.common.exception.CryptoException;
import org.loong.crypto.common.exception.InvalidKeyException;
import org.loong.crypto.core.algorithm.SignatureAlgorithm;
import org.loong.crypto.core.utils.RSAKeyUtils;
import org.loong.crypto.service.core.provider.Verifier;
import org.loong.crypto.service.core.provider.impl.RSAProvider;

import cn.hutool.crypto.asymmetric.Sign;

/**
 * RSA verifier of signature.
 */
public class RSAVerifier extends RSAProvider implements Verifier {

    /**
     * The public key.
     */
    private RSAPublicKey publicKey;

    /**
     * Creates a new verifier.
     *
     * @param keyBytes the public key bytes. Must not be {@code null}.
     */
    public RSAVerifier(final byte[] keyBytes) {
        this(RSAKeyUtils.toRSAPublicKey(keyBytes));
    }

    /**
     * Creates a new verifier.
     *
     * @param publicKey the public key. Must not be {@code null}.
     */
    public RSAVerifier(final RSAPublicKey publicKey) {
        if (publicKey == null) {
            throw new InvalidKeyException("The public RSA key must not be null.");
        }

        if (!"RSA".equalsIgnoreCase(publicKey.getAlgorithm())) {
            throw new InvalidKeyException("The public key algorithm must be RSA.");
        }

        this.publicKey = publicKey;
    }

    @Override
    public boolean verify(final SignatureAlgorithm algorithm, final byte[] data, final byte[] signature) throws CryptoException {
        try {
            Sign verifier = new Sign(algorithm.getName(), null, publicKey);
            if (StringUtils.endsWith(algorithm.getName(), "RSASSA-PSS")) {
                PSSParameterSpec pssSpec = getPSSParameterSpec(algorithm);
                if (pssSpec != null) {
                    verifier.setParameter(pssSpec);
                }
            }
            return verifier.verify(data, signature);
        } catch (cn.hutool.crypto.CryptoException e) {
            return false;
        }
    }
}
